package web.jdbc;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.Map;

import web.clazz.Clazz;
/**用于数据处理
 *<p>
 *
 * {@link Delete}
 * {@link Insert}
 * {@link Select}
 * {@link Update}
 * </p>
 *  @author 乐渊
 * 	@version 1.0
 *  @see QuerySQL
 * */
public class DataOperator<T> {
	
	public static LinkedList<String> columns = new LinkedList<>();
	public static LinkedList<Object> values = new LinkedList<>();
	
	public static String keyColumn;//主键列名
	public static Object keyValue;//主键值
	
	/**为自定义SQL提取返回结果ResultSet的数据，从ResultSet中提取值一Object类型返回，用于保存到Entity实体中。
	 * 在{@link QuerySQL}中，通过反射来调用Entity成员的get方法，为Entity对象赋值。
	 * @param rs 执行过SQL返回的ResultSet
	 * @param obj 对应实体变量名的值
	 * @return o 返回ResultSet中与Entity对应属性得志
	 * */
	public Object getData(Object obj, ResultSet rs){
		Object o = null;
		String name = "";
		if(obj instanceof Field){
			Field field = (Field) obj;
			String type = field.getType().getName();
			type = type.substring(type.lastIndexOf(".")+1, type.length());
			name = field.getName();
		}else{
			name = obj.toString();
		}
		
		try {
			o = rs.getObject(name);
			
			if(o instanceof Integer){
				o = rs.getInt(name);
			}else if(o instanceof String){
				o = rs.getString(name);
			}else if(o instanceof Double){
				o = rs.getDouble(name);
			}else if(o instanceof Long){
				o = rs.getLong(name);
			}else if(o instanceof Short){
				o = rs.getShort(name);
			}else if(o instanceof Float){
				o = rs.getFloat(name);
			}else if(o instanceof Timestamp){
				o = rs.getTimestamp(name);
			}else if(o instanceof Date){
				o = rs.getDate(name);
			}else if(o instanceof java.util.Date){
				o = rs.getDate(name);
			}else if(o instanceof BigDecimal){
				o = rs.getBigDecimal(name);
			}else if(o instanceof Time){
				o = rs.getTime(name);
			}else if(o instanceof byte[]){
				o = rs.getBlob(name);
			}else if(o instanceof Array){
				o = rs.getArray(name);
			}else{
				if(o!=null){
					System.out.println("DataOperator.getData(...)中没有合适的对象存储列名为："+name+"的值！(请扩展框架)");
					o=null;
				}
			}
		} catch (SQLException e) {
				e.printStackTrace();
		}
		return o;
	}
	
	/**PreparedStatement数据填充
	 * @param ps
	 * @param index
	 * @param value
	 * */
	public static void setData(PreparedStatement ps,int index,Object value){
		
		try {
			if(value instanceof Integer){
				ps.setInt(index,(Integer)value);
			}else if(value instanceof String){
				ps.setString(index,(String)value);
			}else if(value instanceof Double){
				ps.setDouble(index,(Double)value);
			}else if(value instanceof Long){
				ps.setLong(index,(Long)value);
			}else if(value instanceof Short){
				ps.setShort(index,(Short)value);
			}else if(value instanceof Float){
				ps.setFloat(index,(Float)value);
			}else if(value instanceof Date){
				ps.setDate(index,(Date)value);
			}else if(value instanceof java.util.Date){
				//ps.setDate(index,new Date(((java.util.Date)value).getTime()));//没有具体时间，只有日期
				ps.setTimestamp(index,new Timestamp(((java.util.Date)value).getTime()));
			}else if(value instanceof BigDecimal){
				ps.setBigDecimal(index,(BigDecimal)value);
			}else if(value instanceof Time){
				ps.setTime(index,(Time)value);
			}else if(value instanceof Timestamp){
				ps.setTimestamp(index,(Timestamp)value);
			}else if(value instanceof Blob){
				ps.setBlob(index,(Blob)value);
			}else if(value instanceof Array){
				ps.setArray(index,(Array)value);
			}else{
				if(value != null){
					System.out.println("DataOperator.setData(...)没有合适的对象存储："+value+"！(请扩展框架)");
					value=null;
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 初始化LinkedList，为添加数据时的PreparedStatement数据填充做准备
	 * @param t
	 * @param clazz
	 */
	public void collectData(T t, Clazz clazz) {
		columns.clear();
		values.clear();
		
		keyColumn = null;
	    keyValue = null;
	    
	    try
	    {
	      Map<Field, String> map = clazz.getFields();
	      keyColumn = (String)clazz.getKey().get(clazz.getKey().keySet().iterator().next());
	      Map<Field, Method> mapt = FieldsGetSet.getFieldGetOrSet(t.getClass(), "get");
	      
	      Method keyMethod = null;
	      for (Field field : mapt.keySet())
	      {
	        for (Field f : map.keySet()) {
	          if (field.equals(f))
	          {
	            Object result = ((Method)mapt.get(f)).invoke(t, new Object[0]);
	            if (result != null)
	            {
	              columns.add((String)clazz.getFields().get(f));
	              values.add(result);
	            }
	          }
	        }
	        if (((String)clazz.getKey().keySet().iterator().next()).equals(field.getName())) {
	          keyMethod = (Method)mapt.get(field);
	        }
	      }
	      keyValue = keyMethod.invoke(t, new Object[0]);
	    }catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}
	}
	
	/**通过实体参数的类型，把从jsp获取到的参数强转为该类型的值返回
	 * @param type 参数类型
	 * @param input 参数值
	 * @return result 转换后的参数值
	 * */
	public static Object parseData(Class<?> type,String input){
		Object result = null;
		if(input != null){
			if(type == Integer.class){
				result = Integer.parseInt(input);
			}else if(type == String.class){
				result = input;
			}else if(type == Double.class){
				result = Double.valueOf(input);
			}else if(type == Long.class){
				result = Long.valueOf(input);
			}else if(type == Short.class){
				result = Short.valueOf(input);
			}else if(type == Float.class){
				result = Float.valueOf(input);
			}else if(type == Date.class){
				result = Date.valueOf(input);
			}else if(type == BigDecimal.class){
				result = BigDecimal.valueOf(Double.valueOf(input));
			}else if(type == Time.class){
				result = Time.valueOf(input);
			}else if(type == Timestamp.class){
				result = Timestamp.valueOf(input);
			}else if(type == Blob.class){
				result = input.getBytes();
			}
		}
		return result;
	}
}
